﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.ServiceProcess;
using System.Drawing.Imaging;
using ZXing;

using Shadowsocks.Model;

namespace ssgui
{
    public partial class ConfigForm : Form
    {
        Configuration config;
        int oldSelectionIndex = -1;
        ServiceController shadowsocksController;

        public ConfigForm()
        {
            InitializeComponent();

            this.Icon = Icon.FromHandle(Resources.ssw128.GetHicon());

            shadowsocksController = new ServiceController();
            shadowsocksController.ServiceName = "Shadowsocks";

            this.config = Configuration.Load();
            updateConfigToForm(config);
            ServersListBox.SelectedIndexChanged += new EventHandler(ServersListBox_SelectedIndexChanged);
        }

        private void updateConfigToForm(Configuration config)
        {
            ServersListBox.Items.Clear();
            ServersListBox.Items.AddRange(config.configs.ConvertAll<string>(o => o.remarks).ToArray());
            ServersListBox.SelectedIndex = config.index;
            this.oldSelectionIndex = config.index;

            var currentServer = config.configs[config.index];
            IPTextBox.Text = currentServer.server;
            ServerPortTextBox.Text = currentServer.server_port.ToString();
            PasswordTextBox.Text = currentServer.password;
            EncryptionSelect.Text = currentServer.method.ToLower();
            RemarksTextBox.Text = currentServer.remarks;

            ProxyPortTextBox.Text = config.localPort.ToString();
        }

        private void saveConfigToFile(Configuration config)
        {
            //TODO: validate config;
            Configuration.Save(config);
        }

        private void saveFormToConfig(Configuration config, int toIndex)
        {
            //Read config from form
            var newServer = new Server();
            newServer.server = IPTextBox.Text;
            int.TryParse(ServerPortTextBox.Text, out newServer.server_port);
            newServer.password = PasswordTextBox.Text;
            newServer.method = EncryptionSelect.Text;
            newServer.remarks = RemarksTextBox.Text;

            if (oldSelectionIndex >= config.configs.Count)
            {
                config.configs.Add(newServer);
            }
            else
            {
                config.configs[oldSelectionIndex] = newServer;
            }

            int.TryParse(ProxyPortTextBox.Text, out config.localPort);

            config.index = ServersListBox.SelectedIndex;

        }

        private void ServersListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            ServersListBox.SelectedIndexChanged -= ServersListBox_SelectedIndexChanged;
            saveFormToConfig(config, oldSelectionIndex);

            oldSelectionIndex = ServersListBox.SelectedIndex;

            //Load config to form
            updateConfigToForm(config);
            ServersListBox.SelectedIndexChanged += new EventHandler(ServersListBox_SelectedIndexChanged);
        }

        private void AddButton_Click(object sender, EventArgs e)
        {
            var server = new Server();
            addServer(server);
        }

        private void addServer(Server server)
        {
            config.configs.Add(server);

            ServersListBox.SelectedIndexChanged -= ServersListBox_SelectedIndexChanged;
            ServersListBox.Items.Add("New Server");
            ServersListBox.SelectedIndex = ServersListBox.Items.Count - 1;
            saveFormToConfig(config, oldSelectionIndex);

            IPTextBox.Text = server.server;
            ServerPortTextBox.Text = server.server_port.ToString();
            PasswordTextBox.Text = server.password;
            EncryptionSelect.Text = server.method;
            RemarksTextBox.Text = server.remarks;

            oldSelectionIndex = ServersListBox.SelectedIndex;
            ServersListBox.SelectedIndexChanged += ServersListBox_SelectedIndexChanged;
        }

        private void DeleteButton_Click(object sender, EventArgs e)
        {
            ServersListBox.SelectedIndexChanged -= ServersListBox_SelectedIndexChanged;
            var deletedIndex = ServersListBox.SelectedIndex;
            ServersListBox.Items.RemoveAt(deletedIndex);
            config.configs.RemoveAt(deletedIndex);

            if (deletedIndex >= ServersListBox.Items.Count-1)
            {
                ServersListBox.SelectedIndex = 0;
            }
            else
            {
                ServersListBox.SelectedIndex = deletedIndex;
            }

            config.index = ServersListBox.SelectedIndex;
            int.TryParse(ProxyPortTextBox.Text, out config.localPort);
            updateConfigToForm(config);

            oldSelectionIndex = ServersListBox.SelectedIndex;
            ServersListBox.SelectedIndexChanged+=ServersListBox_SelectedIndexChanged;
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            base.OnFormClosing(e);
            saveFormToConfig(config, ServersListBox.SelectedIndex);
            saveConfigToFile(config);
            Application.Exit();
        }

        private void StartButton_Click(object sender, EventArgs e)
        {
            shadowsocksController.Refresh();
            if (shadowsocksController.Status == ServiceControllerStatus.Stopped)
            {
                shadowsocksController.Start();
            }
        }

        private void StopButton_Click(object sender, EventArgs e)
        {
            shadowsocksController.Refresh();
            if (shadowsocksController.Status == ServiceControllerStatus.Running)
            {
                shadowsocksController.Stop();
            }
        }

        private void RestartButton_Click(object sender, EventArgs e)
        {
            shadowsocksController.Refresh();
            if (shadowsocksController.Status == ServiceControllerStatus.Running)
            {
                shadowsocksController.Stop();
                shadowsocksController.WaitForStatus(ServiceControllerStatus.Stopped);
                shadowsocksController.Start();
            }
        }

        private void scanQrCodeButton_Click(object sender, EventArgs e)
        {
            var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
            var gfxScreenshot = Graphics.FromImage(bmpScreenshot);
            gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
                                        Screen.PrimaryScreen.Bounds.Y,
                                        0,
                                        0,
                                        Screen.PrimaryScreen.Bounds.Size,
                                        CopyPixelOperation.SourceCopy);
            
            var reader = new BarcodeReader();
            reader.Options.PossibleFormats = new List<BarcodeFormat>
            {
                BarcodeFormat.QR_CODE
            };
            var result = reader.Decode(bmpScreenshot);
            if (result != null)
            {
                var server = new Server(result.Text);
                addServer(server);
            }
            else
            {
                MessageBox.Show("Unable to decode. Please move the image to screen center");
            }
        }

        private void GenQrCodeButton_Click(object sender, EventArgs e)
        {
            IBarcodeWriter writer = new BarcodeWriter
            {
                Format = BarcodeFormat.QR_CODE,
                Options = new ZXing.QrCode.QrCodeEncodingOptions
                {
                    Width = 400,
                    Height = 400
                }
            };
            var code = new Bitmap(writer.Write(config.GetCurrentServer().toURI()));
            Form dlg = new qrCode();
            foreach (Control c in dlg.Controls)
            {
                if (c is PictureBox)
                {
                    (c as PictureBox).Image = code;
                    break;
                }
            }
            dlg.ShowDialog();
        }

        private void SaveButton_Click(object sender, EventArgs e)
        {
            saveFormToConfig(config, ServersListBox.SelectedIndex);
            saveConfigToFile(config);
        }
    }
}
